import 'package:built_collection/built_collection.dart';
import 'package:backend.core/core/domain/entities/api/app_store/api_app_store_one_time_purchased_item.dart';
import 'package:backend.core/core/domain/entities/api/app_store/api_app_store_purchased_item.dart';
import 'package:backend.core/core/domain/entities/api/app_store/api_app_store_purchased_subscription.dart';
import 'package:backend.core/core/domain/entities/api/app_store/api_app_store_purchased_subscription_expiration_reason.dart';
import 'package:backend.core/core/domain/entities/api/app_store/api_app_store_purchased_subscription_status.dart';
import 'package:backend.core/core/domain/entities/app_store/app_store_one_time_purchased_item_transaction.dart';
import 'package:backend.core/core/domain/entities/app_store/app_store_purchased_subscription_info.dart';
import 'package:backend.core/core/domain/entities/app_store/app_store_purchased_subscription_transaction.dart';
import 'package:backend.core/core/domain/entities/app_store/app_store_transaction.dart';
import 'package:backend.purchases/domain/helpers/api/app_store/create_api_app_store_expiration_reason_from_internal_one.dart';
import 'package:backend.purchases/domain/helpers/api/app_store/create_api_app_store_one_time_purchase_item_transaction_from_internal_one.dart';
import 'package:backend.purchases/domain/helpers/api/app_store/create_api_app_store_price_increase_status_from_internal_one.dart';
import 'package:backend.purchases/domain/helpers/api/app_store/create_api_app_store_purchased_subscription_transaction_from_internal_one.dart';

abstract class CreateApiAppStorePurchasedItemsFromInternalOnes {
  BuiltList<ApiAppStorePurchasedItem> call({
    required BuiltList<AppStoreTransaction> transactions,
    required BuiltList<AppStorePurchasedSubscriptionInfo> purchasedSubscriptionInfos,
  });
}

class CreateApiAppStorePurchasedItemsFromInternalOnesImpl
    implements CreateApiAppStorePurchasedItemsFromInternalOnes {
  const CreateApiAppStorePurchasedItemsFromInternalOnesImpl({
    required CreateApiAppStorePurchasedSubscriptionTransactionFromInternalOne
        createApiAppStorePurchasedSubscriptionTransactionFromInternalOne,
    required CreateApiAppStoreOneTimePurchasedItemTransactionFromInternalOne
        createApiAppStoreOneTimePurchasedItemTransactionFromInternalOne,
    required CreateApiAppStorePurchasedSubscriptionPriceIncreaseStatusFromInternalOne
        createApiAppStorePurchasedSubscriptionPriceIncreaseStatusFromInternalOne,
    required CreateApiAppStorePurchasedSubscriptionExpirationReasonFromInternalOne
        createApiAppStorePurchasedSubscriptionExpirationReasonFromInternalOne,
  })  : _createApiAppStorePurchasedSubscriptionTransactionFromInternalOne =
            createApiAppStorePurchasedSubscriptionTransactionFromInternalOne,
        _createApiAppStoreOneTimePurchasedItemTransactionFromInternalOne =
            createApiAppStoreOneTimePurchasedItemTransactionFromInternalOne,
        _createApiAppStorePurchasedSubscriptionPriceIncreaseStatusFromInternalOne =
            createApiAppStorePurchasedSubscriptionPriceIncreaseStatusFromInternalOne,
        _createApiAppStorePurchasedSubscriptionExpirationReasonFromInternalOne =
            createApiAppStorePurchasedSubscriptionExpirationReasonFromInternalOne;

  final CreateApiAppStorePurchasedSubscriptionTransactionFromInternalOne
      _createApiAppStorePurchasedSubscriptionTransactionFromInternalOne;
  final CreateApiAppStoreOneTimePurchasedItemTransactionFromInternalOne
      _createApiAppStoreOneTimePurchasedItemTransactionFromInternalOne;
  final CreateApiAppStorePurchasedSubscriptionPriceIncreaseStatusFromInternalOne
      _createApiAppStorePurchasedSubscriptionPriceIncreaseStatusFromInternalOne;
  final CreateApiAppStorePurchasedSubscriptionExpirationReasonFromInternalOne
      _createApiAppStorePurchasedSubscriptionExpirationReasonFromInternalOne;

  @override
  BuiltList<ApiAppStorePurchasedItem> call({
    required BuiltList<AppStoreTransaction> transactions,
    required BuiltList<AppStorePurchasedSubscriptionInfo> purchasedSubscriptionInfos,
  }) {
    final apiPurchasedItems = <ApiAppStorePurchasedItem>[];

    final purchasedSubscriptionTransactionMap =
        <String, List<AppStorePurchasedSubscriptionTransaction>>{};

    for (final transaction in transactions) {
      if (transaction is AppStoreOneTimePurchasedItemTransaction) {
        final apiOneTimePurchasedItemTransaction =
            _createApiAppStoreOneTimePurchasedItemTransactionFromInternalOne(
          oneTimePurchasedItemTransaction: transaction,
        );

        final apiOneTimePurchasedItem = ApiAppStoreOneTimePurchasedItem(
          purchaseItemSku: transaction.purchaseItemSku,
          test: transaction.test,
          transactionId: transaction.id,
          revoked: transaction.revocationInfo != null,
          transaction: apiOneTimePurchasedItemTransaction,
        );

        apiPurchasedItems.add(apiOneTimePurchasedItem);
      } else if (transaction is AppStorePurchasedSubscriptionTransaction) {
        purchasedSubscriptionTransactionMap[transaction.originalTransactionId] ??= [];
        purchasedSubscriptionTransactionMap[transaction.originalTransactionId]!.add(transaction);
      }
    }

    for (final purchasedSubscriptionInfo in purchasedSubscriptionInfos) {
      final apiPriceIncreaseStatus =
          _createApiAppStorePurchasedSubscriptionPriceIncreaseStatusFromInternalOne(
        priceIncreaseStatus: purchasedSubscriptionInfo.priceIncreaseStatus,
      );

      ApiAppStorePurchasedSubscriptionExpirationReason? apiExpirationReason;

      if (purchasedSubscriptionInfo.expirationReason != null) {
        apiExpirationReason =
            _createApiAppStorePurchasedSubscriptionExpirationReasonFromInternalOne(
          expirationReason: purchasedSubscriptionInfo.expirationReason!,
        );
      }

      final transactions =
          purchasedSubscriptionTransactionMap[purchasedSubscriptionInfo.originalTransactionId];

      if (transactions == null) {
        continue;
      }

      final unrevokedTransactions = transactions.where((transaction) {
        return transaction.revocationInfo == null;
      }).toList();

      AppStorePurchasedSubscriptionTransaction? lastUnrevokedTransaction;

      if (unrevokedTransactions.isNotEmpty) {
        lastUnrevokedTransaction = unrevokedTransactions.last;
      }

      final currentTime = DateTime.now().toUtc();

      final ApiAppStorePurchasedSubscriptionStatus status;

      if (purchasedSubscriptionInfo.isInBillingRetryPeriod) {
        status = ApiAppStorePurchasedSubscriptionStatus.inBillingRetryPeriod;
      } else if (purchasedSubscriptionInfo.gracePeriodExpirationTime != null) {
        status = ApiAppStorePurchasedSubscriptionStatus.inGracePeriod;
      } else if (lastUnrevokedTransaction == null) {
        status = ApiAppStorePurchasedSubscriptionStatus.revoked;
      } else if (lastUnrevokedTransaction.expirationTime.isBefore(currentTime)) {
        status = ApiAppStorePurchasedSubscriptionStatus.expired;
      } else {
        status = ApiAppStorePurchasedSubscriptionStatus.active;
      }

      final apiTransactions = transactions.map((transaction) {
        return _createApiAppStorePurchasedSubscriptionTransactionFromInternalOne(
          purchasedSubscriptionTransaction: transaction,
        );
      }).toList();

      apiTransactions.sort((first, second) {
        return first.time.compareTo(second.time);
      });

      final apiPurchasedSubscription = ApiAppStorePurchasedSubscription(
        purchaseItemSku: purchasedSubscriptionInfo.purchaseItemSku,
        originalTransactionId: purchasedSubscriptionInfo.originalTransactionId,
        autoRenewalEnabled: purchasedSubscriptionInfo.autoRenewalEnabled,
        status: status,
        expirationTime: lastUnrevokedTransaction?.expirationTime,
        priceIncreaseStatus: apiPriceIncreaseStatus,
        test: purchasedSubscriptionInfo.test,
        expirationReason: apiExpirationReason,
        gracePeriodExpirationTime: purchasedSubscriptionInfo.gracePeriodExpirationTime,
        transactions: apiTransactions.toBuiltList(),
      );

      apiPurchasedItems.add(apiPurchasedSubscription);
    }

    return apiPurchasedItems.toBuiltList();
  }
}
